package edu.hawaii.jmotif.sequitur.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.JPanel;
import org.hackystat.utilities.stacktrace.StackTrace;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import edu.hawaii.jmotif.sequitur.logic.MotifChartData;
import edu.hawaii.jmotif.sequitur.logic.SAXPosition;
import edu.hawaii.jmotif.sequitur.logic.SAXString;
import edu.hawaii.jmotif.timeseries.TSException;

public class SequiturRuleChartPanel extends JPanel implements PropertyChangeListener {

  /** Fancy serial. */
  private static final long serialVersionUID = 5334407476500195779L;

  /** The chart container. */
  private JFreeChart chart;

  /** The plot itself. */
  private XYPlot plot;

  /** Current chart data instance. */
  private MotifChartData chartData;

  /**
   * Constructor.
   */
  public SequiturRuleChartPanel() {
    super();
  }

  public void set(MotifChartData chartData) {
    this.chartData = chartData;
  }

  /**
   * create the chart for the original time series
   * 
   * @return a JFreeChart object of the chart
   */
  private void chartIntervals(ArrayList<double[]> intervals) {

    // making the data
    //
    XYSeriesCollection collection = new XYSeriesCollection();
    int counter = 0;
    for (double[] series : intervals) {
      collection.addSeries(toSeries(counter++, series));
    }

    // set the renderer
    //
    XYLineAndShapeRenderer xyRenderer = new XYLineAndShapeRenderer(true, false);
    xyRenderer.setSeriesPaint(0, new Color(0, 0, 0));
    xyRenderer.setBaseStroke(new BasicStroke(3));

    // X - the time axis
    //
    NumberAxis timeAxis = new NumberAxis();
    // timeAxis.setLabel("Time");

    // Y axis
    //
    NumberAxis valueAxis = new NumberAxis();
    valueAxis.setAutoRangeIncludesZero(false);
    // valueAxis.setLabel("Values");

    // put these into collection of dots
    //
    this.plot = new XYPlot(collection, timeAxis, valueAxis, xyRenderer);

    // finally, create the chart
    this.chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);

    // and put it on the show
    ChartPanel chartPanel = new ChartPanel(this.chart);
    chartPanel.setMinimumDrawWidth(0);
    chartPanel.setMinimumDrawHeight(0);
    chartPanel.setMaximumDrawWidth(1920);
    chartPanel.setMaximumDrawHeight(1200);

    // cleanup all the content
    //
    this.removeAll();

    // put the chart on show
    //
    this.add(chartPanel);

    // not sure if I need this
    //
    this.validate();
    this.repaint();

  }

  private XYSeries toSeries(int index, double[] series) {
    XYSeries res = new XYSeries("series" + String.valueOf(index));
    for (int i = 0; i < series.length; i++) {
      res.add(i, series[i]);
    }
    return res;
  }

  /**
   * highlight the original time series sequences of a rule
   * 
   * @param index index of the rule in the sequitur table
   */
  protected void chartIntervalsForRule(String rule) {

    try {
      System.out.println("Selected rule: " + rule);

      SAXString sax = new SAXString(chartData.getFreqData(), " ");

      String textRule = chartData.convert2OriginalSAXAlphabet('1', rule);
      
      ArrayList<SAXPosition> arrPos = sax.getRulePositions(chartData.getSAXWindowSize(),
          chartData.getSAXPaaSize(), textRule);
      System.out.println("Size: " + arrPos.size() + " - Positions: " + arrPos);

      ArrayList<double[]> intervals = new ArrayList<double[]>();

      for (SAXPosition saxPos : arrPos) {
        intervals.add(extractInterval(saxPos.getStartPos(), saxPos.getEndPos()));
      }

      chartIntervals(intervals);

    }
    catch (TSException e) {
      System.err.println(StackTrace.toString(e));
    }

  }

  private double[] extractInterval(int startPos, int endPos) throws TSException {
    if (this.chartData.getOriginalTimeseries().size() <= (endPos - startPos)) {
      return this.chartData.getOriginalTimeseries()
          .subsection(0, this.chartData.getOriginalTimeseries().size() - 1).values();
    }
    return this.chartData.getOriginalTimeseries().subsection(startPos, endPos).values();
  }

  @Override
  public void propertyChange(PropertyChangeEvent evt) {
    if (SequiturRulesPanel.FIRING_PROPERTY.equalsIgnoreCase(evt.getPropertyName())) {
      String newlySelectedRaw = (String) evt.getNewValue();
      chartIntervalsForRule(newlySelectedRaw);
    }
  }

}
